package com.atguigu.tingshu.payment.service.impl;

import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.*;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private RSAAutoCertificateConfig config;

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private WxPayV3Config wxPayV3Config;


    @Override
    public boolean refund(String orderNo) {
        //  创建退款对象
        RefundService refundService = new RefundService.Builder().config(config).build();
        //  创建退款请求对象
        CreateRequest createRequest = new CreateRequest();
        createRequest.setOutTradeNo(orderNo);
        createRequest.setOutRefundNo(orderNo);
        AmountReq amountReq = new AmountReq();
        amountReq.setRefund(1l);
        amountReq.setTotal(1l);
        amountReq.setCurrency("CNY");
        createRequest.setAmount(amountReq);
        Refund refund = refundService.create(createRequest);
        //  判断
        if (refund.getStatus().equals(Status.SUCCESS)){
            //  关闭交易记录
            this.paymentInfoService.closePayment(orderNo);
            //  修改订单状态.
            return true;
        }
        return false;
    }

    @Override
    public boolean closePay(String orderNo) {
        //  关闭请求：
        CloseOrderRequest closeRequest = new CloseOrderRequest();
        closeRequest.setMchid(wxPayV3Config.merchantId);
        closeRequest.setOutTradeNo(orderNo);

        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 方法没有返回值，意味着成功时API返回204 No Content
        service.closeOrder(closeRequest);
        return false;
    }

    @Override
    public Transaction wxNotify(HttpServletRequest request) {
        //	业务实现：
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatPayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        //	获取请求体：
        String requestBody = PayUtil.readData(request);
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatPayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();
        //	构建对象NotificationParser
        NotificationParser parser = new NotificationParser(config);
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            //	返回对象
            return transaction;
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
            log.error("sign verification failed", e);
            throw new GuiguException(ResultCodeEnum.UNAUTHORIZED);
        }
    }


    @Override
    public void queryPayStatus(String orderNo) {
        //	创建根据商户订单号 获取到请求对象
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayV3Config.merchantId);
        queryRequest.setOutTradeNo(orderNo);
        //	创建服务拓展类对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        try {
            //	Transaction result = service.queryOrderById(queryRequest);
            Transaction result = service.queryOrderByOutTradeNo(queryRequest);
            System.out.println(result.getTradeState());
            //	如何判断是否支付成功.
            System.out.println(result.getTradeType().name());
            if (result.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
                //	支付成功. -- 修改支付交易记录的状态.
                paymentInfoService.updatePaymentStatus(result);
            } else if (result.getTradeState().equals(Transaction.TradeStateEnum.CLOSED)){
                System.out.println("查询...");
            }
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
            throw new GuiguException(e.getHttpStatusCode(), e.getErrorMessage());
        }
    }

    @Override
    public Map<String, Object> createJsapi(String paymentType, String orderNo) {
        //	声明一个map 集合
        Map<String, Object> result = new HashMap();
        OrderInfo orderInfo = new OrderInfo();
        //	如果走充值业务：那么订单应该是空，
        if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)) {
            //	远程调用订单对象
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult, "订单结果集为空");
            orderInfo = orderInfoResult.getData();
            Assert.notNull(orderInfo, "订单对象为空");
            //	判断如果订单已经取消，不能生成二维码！
            if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderInfo.getOrderStatus())) {
                return result;
            }
        }
        //	保存支付交易记录：
        PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(orderInfo, paymentType, orderNo);
        //	创建服务拓展类对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 填充预下单参数包的路径看对了，jsapi
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //	设置金额：
        //	amount.setTotal(Integer.parseInt(orderInfo.getOrderAmount().toString()));
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.merchantId);
        request.setDescription("测试商品标题");
        //	商户订单号
        request.setOutTradeNo(orderNo);
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        //	设置过期时间：给多少?  先给一个固定值：5 订单过期时间 10 {1} 取小的时间 ： 取订单过期时间！
        //	request.setTimeExpire(); 绝对时间
        Date date = new LocalDateTime(new Date()).plusSeconds(10).toDate(TimeZone.getTimeZone(ZoneId.of("+8")));
        //  线程不安全！--- 多线程不能使用！
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-DDTHH:mm:ss+TIMEZONE");
        //        Calendar calendar = Calendar.getInstance();
        //        calendar.add(Calendar.SECOND,10);
        //        Date time = calendar.getTime();
        String format = simpleDateFormat.format(date);
        System.out.println("date:"+date);
        //  request.setTimeExpire("2024-01-09T11:49:56+08:00");
        //	设置支付者： payer
        Payer payer = new Payer();
        //	获取用户的openId
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(paymentInfo.getUserId());
        Assert.notNull(userInfoVoResult, "用户信息结果集为空");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "用户信息为空");
        //	设置openId
        payer.setOpenid(userInfoVo.getWxOpenId());
        request.setPayer(payer);
        //	调用方法
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        //	返回数据。
        result.put("timeStamp", response.getTimeStamp()); // 时间戳
        result.put("nonceStr", response.getNonceStr());   // 随机字符串
        result.put("package", response.getPackageVal());  // 订单详情扩展字符串
        result.put("signType", response.getSignType());   // 签名方式
        result.put("paySign", response.getPaySign());     // 签名
        //	必须返回数据
        return result;
    }
}
